package websocket2

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/gorilla/websocket"
	"log"
	"net/http"
	"strings"
	"sync"
	"time"
)

type Connection struct {
	wsConn     *websocket.Conn
	inChan     chan []byte
	outChan    chan []byte
	closeChan  chan byte
	isClosed   bool
	lock       sync.Mutex
	isServer   bool
	header     http.Header
	clientId   string
	clientCode string
	timestamp  int64
}

func InitConnection(wsConn *websocket.Conn, isServer bool, header http.Header) (conn *Connection, err error) {
	if wsConn == nil {
		return
	}
	conn = &Connection{
		wsConn:    wsConn,
		inChan:    make(chan []byte, 1000),
		outChan:   make(chan []byte, 1000),
		closeChan: make(chan byte, 1),
		isServer:  isServer,
		header:    header,
	}
	go conn.readLoop()
	go conn.writeLoop()
	return
}

func (conn *Connection) ReadMessage() (data []byte, err error) {
	select {
	case data = <-conn.inChan:
	case <-conn.closeChan:
		err = errors.New(fmt.Sprintf("read connection is closed"))
	}
	return
}
func (conn *Connection) WriteMessage(data []byte) (err error) {
	select {
	case conn.outChan <- data:
	case <-conn.closeChan:
		err = errors.New(fmt.Sprintf("write connection is closed"))
		log.Println(err)
	}
	return
}
func (conn *Connection) Id() string {
	return conn.clientId
}
func (conn *Connection) Name() string {
	return conn.clientCode
}
func (conn *Connection) Close() {
	if conn == nil || conn.wsConn == nil {
		return
	}
	//线程安全,可以重入的close(可多次执行)
	conn.wsConn.Close()
	//通道的close只能执行一次 需要枷锁
	conn.lock.Lock()
	if !conn.isClosed {
		close(conn.closeChan)
		conn.isClosed = true
		if conn.isServer {
			log.Printf("clientId:[%s] connection【关闭】成功!", conn.clientId)
			wsMap.Delete(conn.clientId)
		}
	}
	conn.lock.Unlock()
}
func (conn *Connection) IsClosed() bool {
	return conn.isClosed
}

func (conn *Connection) CloseChan() chan byte {
	return conn.closeChan
}
func (conn *Connection) readLoop() {
	var (
		data       []byte
		err        error
		clientId   string
		clientCode string
	)
	for {
		if _, data, err = conn.wsConn.ReadMessage(); err != nil {
			log.Printf("wsConn read message error:[%v]", err)
			goto ERR
		}
		if b := bytes.Equal(defaultHead, data[:4]); b {
			dataLen := byte2int(data[4:8]) //前4个字节是固定协议头 接着4个字节是数据(act+实际的数据)长度
			act, ret := Parse(data[8 : 8+dataLen])
			switch act {
			case ActResponseClientId:
				d := string(ret)
				//fmt.Println("收到客户端响应clientInfo:", d)
				clientId = strings.Split(d, ",")[0]
				clientCode = strings.Split(d, ",")[1]
				log.Printf("收到客户端 actResponseClientId[%s],clientCode:[%s] join进wsMap", clientId, clientCode)
				conn.clientId = clientId
				conn.clientCode=clientCode
				conn.timestamp = time.Now().Unix()
				join(clientId, conn)
			case ActResponseHeartBeat:
				processHeartbeat(clientId, ret, conn)
			default:
				select {
				case conn.inChan <- ret:
				case <-conn.closeChan:
					//closeChan关闭的时候回进入到这个case
					goto ERR
				}
			}
		}

	}
ERR:
	conn.Close()
}
func (conn *Connection) writeLoop() {
	var (
		data []byte
		err  error
	)
	for {
		select {
		case data = <-conn.outChan:
		case <-conn.closeChan:
			goto ERR
		}
		if err = conn.wsConn.WriteMessage(websocket.TextMessage, data); err != nil {
			log.Printf("wsConn write message error:[%v]", err)
			goto ERR
		}
	}

ERR:
	conn.Close()
}

/**
被动超时断开连接
 */
func processHeartbeat(clientId string, data []byte, conn *Connection) {
	//log.Printf("收到客户端[%s]响应心跳:[%v]", clientId, byte2int(data))
	now := time.Now().Unix()
	cnow := int64(byte2int(data))
	if cnow+60 < now { //超时15秒开始清理
		wsMap.Delete(clientId)
		conn.Close()
		log.Println("clientId:", clientId, "超时，服务器被动断开连接")
	} else {
		conn.timestamp = now
	}
}
